package xyz.xtt.asset.exception;

import static java.util.stream.Collectors.joining;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.context.MessageSourceResolvable;
import org.springframework.validation.ObjectError;
import org.springframework.validation.method.ParameterValidationResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.constants.ErrorMessage;
import xyz.xtt.common.response.ApiResult;

/**
 * 全局异常处理器
 *
 * @author huqibo
 * @version 1.0 &#064;date 2021/10/18 16:00
 */

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
	private static final String STR = ";";

	/**
	 * 处理所有接口数据验证异常
	 *
	 * @param e       MethodArgumentNotValidException 数据验证异常
	 * @param request HttpServletRequest 请求对象
	 * @return ApiResult<String> 异常响应
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseBody
	public ApiResult<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
		List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
		String errorMsg = formatAllErrorMessages(allErrors);
		String url = request.getRequestURI();
		log.error("GlobalExceptionHandler handleMethodArgumentNotValidException url:{} ex: {}", url, errorMsg, e);
		return ApiResult.failure(ErrorMessage.ARGUMENT_NOT_VALID.getCode(), errorMsg);
	}

	/**
	 * 处理所有接口数据验证异常
	 *
	 * @param e       MethodArgumentNotValidException 数据验证异常
	 * @param request HttpServletRequest 请求对象
	 * @return ApiResult<String> 异常响应
	 */
	@ExceptionHandler(HandlerMethodValidationException.class)
	@ResponseBody
	public ApiResult<String> handlerMethodValidationException(HandlerMethodValidationException e, HttpServletRequest request) {
		List<String> errList = new ArrayList<>();
		List<ParameterValidationResult> allValidationResults = e.getAllValidationResults();
		for (ParameterValidationResult allValidationResult : allValidationResults) {
			List<MessageSourceResolvable> resolvableErrors = allValidationResult.getResolvableErrors();
			String err = resolvableErrors.stream().map(MessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(", "));
			errList.add(err);
		}
		String err = errList.stream().collect(joining(","));
		return ApiResult.failure(ErrorMessage.ARGUMENT_NOT_VALID.getCode(), err);
	}

	/**
	 * 异常消息拼接
	 *
	 * @param errors List<ObjectError> 异常殚表
	 * @return String 异常消息
	 */
	private String formatAllErrorMessages(List<ObjectError> errors) {
		StringBuffer errorMsg = new StringBuffer();
		errors.forEach(error -> errorMsg.append(error.getDefaultMessage()).append(STR));
		return errorMsg.toString();
	}

	/**
	 * 拦截未知的运行时异常
	 *
	 * @param e       RuntimeException 运行时异常
	 * @param request HttpServletRequest 请求对象
	 * @return ApiResult<String> 异常响应
	 */
	@ExceptionHandler(ChainException.class)
	@ResponseBody
	public ApiResult<Void> handleChainException(ChainException e, HttpServletRequest request) {
		String url = request.getRequestURI();
		log.error("requset ChainException: url:{} code:{} msg:{}", url,e.getCode(), e.getMsg() + "\n\tat " + e.getStackTrace()[0] + "\n\tat " + e.getStackTrace()[1]);
		return ApiResult.failure(e);
	}
	/**
	 * 拦截未知的运行时异常
	 *
	 * @param e       RuntimeException 运行时异常
	 * @param request HttpServletRequest 请求对象
	 * @return ApiResult<String> 异常响应
	 */
	@ExceptionHandler(RuntimeException.class)
	@ResponseBody
	public ApiResult<String> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
		String url = request.getRequestURI();
		log.error("requset RuntimeException: {}", url, e);
		return ApiResult.failure(ErrorMessage.UNKNOWN_ERROR.getCode(), ErrorMessage.UNKNOWN_ERROR.getMessage());
	}

	/**
	 * 系统异常
	 */
	@ExceptionHandler(Exception.class)
	@ResponseBody
	public ApiResult<String> handleException(Exception e, HttpServletRequest request) {
		String url = request.getRequestURI();
		log.error("requset Exception: {}", url, e);
		return ApiResult.failure(ErrorMessage.UNKNOWN_ERROR.getCode(), ErrorMessage.UNKNOWN_ERROR.getMessage());
	}
}
